﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AES_File_Encrypt
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Title = "选择第一个bin文件";    
            openFileDialog1.Filter = "Bin file(*.Bin)|*.Bin";   
            openFileDialog1.CheckPathExists = true; 
            if (openFileDialog1.ShowDialog() == DialogResult.OK)   //如果点击确定
            {
                textBox1.Text = openFileDialog1.FileName;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Title = "选择第二个bin文件";
            openFileDialog1.Filter = "Bin file(*.Bin)|*.Bin";
            openFileDialog1.CheckPathExists = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)   //如果点击确定
            {
                textBox2.Text = openFileDialog1.FileName;
            }
        }

        /// <summary>
        /// 判断十六进制字符串hex是否正确
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <returns>true：不正确，false：正确</returns>
        private  bool IsIllegalHexadecimal(string hex)
        {
            const string PATTERN = @"([^A-Fa-f0-9]|\s+?)+";
            return Regex.IsMatch(hex, PATTERN);
        }

        /// <summary>
        /// 把字符串转换成HEX数组  比如 "1234"=> 0X12 0X34
        /// </summary>
        /// <param name="str"></param>
        /// <returns>返回空转换失败</returns>
        public  byte[] ToStringHex(string str)
        {
            str.Replace(" ", "");  //去掉空格
            //如果字符串不是十六进制格式  返回空
            if ((IsIllegalHexadecimal(str) == true) || ((str.Length % 2) != 0) || (str == string.Empty))
            {
                return null;
            }
            byte[] Buff = new byte[str.Length / 2];
            for (int i = 0; i < str.Length / 2; i++)
            {
                string sub = str.Substring(i * 2, 2);
                Buff[i] = Convert.ToByte(sub, 16);
            }
            return Buff;
        }
        /// <summary>
        ///  0xae00cf => "AE00CF "  
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public  string ToHexString(byte[] bytes) // 0xae00cf => "AE00CF "  
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                {
                    strB.Append(bytes[i].ToString("X2") + " ");
                }
                hexString = strB.ToString();
            }
            return hexString;
        }

        /// <summary>
        /// AES加密解密  ECB模式
        /// </summary>
        /// <param name="Mes_IN_OUT">消息的输入及结果输出 必须为16字节的整数倍</param>
        /// <param name="KeyBuff">秘钥缓存 可以为 16、24、36字节</param>
        /// <param name="Encryptmode">真加密   假解密</param>
        /// <returns>返回0成功 其它错误信息</returns>
        private  int AES_Encrypt_Decode_ECB(ref byte[] Mes_IN_OUT, byte[] KeyBuff, bool Encryptmode)
        {
            //if ((Mes_IN_OUT.Length % 16) > 0)
            //{
            //    return 1;
            //}
            if ((KeyBuff.Length != 16) && (KeyBuff.Length != 24) && (KeyBuff.Length != 32))
            {
                return 2;
            }
            //创建一个加密对象  
            AesCryptoServiceProvider AESCrypt = new AesCryptoServiceProvider();
            AESCrypt.Mode = CipherMode.ECB;
            AESCrypt.Padding = PaddingMode.Zeros;
            AESCrypt.Key = KeyBuff; // 装载秘钥  会自动设置秘钥大小
            var AES_Encrypt = Encryptmode ? AESCrypt.CreateEncryptor() : AESCrypt.CreateDecryptor();
            byte[] Buff = AES_Encrypt.TransformFinalBlock(Mes_IN_OUT, 0, Mes_IN_OUT.Length); //读取操作后的结果
            AESCrypt.Clear(); // 清除 
            Mes_IN_OUT = Buff; //拷贝结果
            return 0;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if ((File.Exists(textBox1.Text)==false)&&(File.Exists(textBox2.Text) == false))
            {
                MessageBox.Show("请至少选择一个文件");
                return;
            }
            byte[] AES_KEY = ToStringHex(textBox3.Text);
            if ((AES_KEY==null)||(AES_KEY.Length!=32))
            {
                MessageBox.Show("秘钥输入错误");
                return;
            }
            try
            {
                UInt32 FileSize = 0;
                byte[] TempfileBuff;
                byte[] BinFile0Buff;
                byte[] BinFile1Buff;
                FileStream fileStream;
                if (File.Exists(textBox1.Text) == false)  //如果文件不存在  则直接填充长度 0
                {
                    BinFile0Buff = new byte[] { 0, 0, 0, 0 };  //直接填充4字节 0
                }
                else  //文件存在
                {
                    fileStream = File.OpenRead(textBox1.Text);
                    FileSize = (UInt32)fileStream.Length;
                    TempfileBuff = new byte[FileSize];
                    fileStream.Read(TempfileBuff, 0, (int)fileStream.Length);  //读取文件数据
                    fileStream.Close();
                    AES_Encrypt_Decode_ECB(ref TempfileBuff, AES_KEY, true);  //加密
                    BinFile0Buff = new byte[TempfileBuff.Length + 4];
                    Array.Copy(BitConverter.GetBytes(FileSize), BinFile0Buff, 4);  //拷贝长度
                    Array.Copy(TempfileBuff, 0, BinFile0Buff, 4, TempfileBuff.Length);  //文件加密后的数据
                }


                if (File.Exists(textBox2.Text) == false)
                {
                    BinFile1Buff = new byte[] { 0, 0, 0, 0 };  //直接填充4字节 0
                }
                else
                {
                    fileStream = File.OpenRead(textBox2.Text);
                    FileSize = (UInt32)fileStream.Length;
                    TempfileBuff = new byte[FileSize];
                    fileStream.Read(TempfileBuff, 0, (int)fileStream.Length);  //读取文件数据
                    fileStream.Close();
                    AES_Encrypt_Decode_ECB(ref TempfileBuff, AES_KEY, true);  //加密
                    BinFile1Buff = new byte[TempfileBuff.Length + 4];
                    Array.Copy(BitConverter.GetBytes(FileSize), BinFile1Buff, 4);  //拷贝长度
                    Array.Copy(TempfileBuff, 0, BinFile1Buff, 4, TempfileBuff.Length);  //文件加密后的数据
                }

                byte[] AllFileBuff = new byte[BinFile0Buff.Length + BinFile1Buff.Length];
                Array.Copy(BinFile0Buff, AllFileBuff, BinFile0Buff.Length);
                Array.Copy(BinFile1Buff, 0, AllFileBuff, BinFile0Buff.Length, BinFile1Buff.Length);

                UInt32 CRC_DATA = CCRC32_0X04C11DB7.Get_CRC32_ETH_STM32(0XFFFFFFFF, AllFileBuff);  //计算CRC
                TempfileBuff = AllFileBuff;
                AllFileBuff = new byte[TempfileBuff.Length+4];
                Array.Copy(TempfileBuff, AllFileBuff, TempfileBuff.Length);
                Array.Copy(BitConverter.GetBytes(CRC_DATA),0, AllFileBuff, TempfileBuff.Length, 4);  //在数据后面追加CRC

                Debug.WriteLine(ToHexString(AllFileBuff));

                string AllFileStr = Convert.ToBase64String(AllFileBuff);  //BASE64 加密
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                saveFileDialog1.Filter  = "加密拼接(*.joinBin)|*.joinBin";
                saveFileDialog1.DefaultExt = ".joinBin";
                if (saveFileDialog1.ShowDialog(this) == DialogResult.OK)
                {
                    textBox4.Text = saveFileDialog1.FileName;
                    StreamWriter stream = new StreamWriter(File.Create(textBox4.Text));
                    stream.Write(AllFileStr);
                    stream.Close();
                    MessageBox.Show("加密拼接成功");
                }
            }
            catch (Exception ex)
            {

                MessageBox.Show("加密拼接失败:"+ex.Message);
            }
        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            label1.Text = "" + textBox3.Text.Length;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
        }

        private void button5_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";
        }

        struct JoinBin_Typ
        {
            /// <summary>
            /// 原文件长度
            /// </summary>
            public UInt32 FileSize;

            /// <summary>
            /// 加密后的文件数据
            /// </summary>
            public byte[] FileBuff;
        }

        private void button6_Click(object sender, EventArgs e)
        {
            byte[] AES_KEY = ToStringHex(textBox3.Text);
            if ((AES_KEY == null) || (AES_KEY.Length != 32))
            {
                MessageBox.Show("秘钥输入错误");
                return;
            }
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            List<JoinBin_Typ> UpdataList = new List<JoinBin_Typ>();
            openFileDialog1.Title = "请选择加密拼接后的文件";
            openFileDialog1.Filter = "加密拼接(*.joinBin)|*.joinBin";
            openFileDialog1.CheckPathExists = true;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)   //如果点击确定
            {
                try
                {
                    StreamReader streamReader = new StreamReader(openFileDialog1.FileName);
                    string str = streamReader.ReadToEnd();
                    streamReader.Close();
                    byte[] FileBytes = Convert.FromBase64String(str);
                    Debug.WriteLine(ToHexString(FileBytes));
                    byte[] TempBuff = new byte[FileBytes.Length - 4]; //去掉CRC后的数据 拼接的原始数据
                    Array.Copy(FileBytes, TempBuff, TempBuff.Length);
                    if (((UInt32)BitConverter.ToInt32(FileBytes, FileBytes.Length - 4)) != CCRC32_0X04C11DB7.Get_CRC32_ETH_STM32(0XFFFFFFFF, TempBuff))
                    {
                        MessageBox.Show("固件文件错误");
                        return;
                    }
                    JoinBin_Typ joinBin_Typ = new JoinBin_Typ();
                    UInt32 File0Szie = 0;
                    File0Szie = (UInt32)BitConverter.ToInt32(FileBytes, 0); //第一个文件的长度
                    joinBin_Typ.FileSize = File0Szie;   //原文件数据长度
                    Debug.WriteLine("第一个文件长度:" + File0Szie);
                    if (File0Szie > 0)
                    {
                        File0Szie = (UInt32)((File0Szie + 0X0F) & (~0X0F));  //得到文件的长度
                        joinBin_Typ.FileBuff = new byte[File0Szie];
                        Array.Copy(TempBuff, 4, joinBin_Typ.FileBuff, 0, joinBin_Typ.FileBuff.Length);
                    }
                    else  //长度为空
                    {
                        joinBin_Typ.FileBuff = new byte[0];
                    }
                    UpdataList.Add(joinBin_Typ);
                    Debug.WriteLine("第一个文件: " + ToHexString(UpdataList[0].FileBuff));

                    UInt32 File1Szie = 0;
                    File1Szie = (UInt32)BitConverter.ToInt32(FileBytes, (int)(4 + File0Szie)); //第二个文件的长度
                    joinBin_Typ.FileSize = File1Szie;   //原文件数据长度
                    Debug.WriteLine("第二个文件长度:" + File1Szie);
                    if (File1Szie > 0)
                    {
                        File1Szie = (UInt32)((File1Szie + 0X0F) & (~0X0F));  //得到文件的长度
                        joinBin_Typ.FileBuff = new byte[File1Szie];
                        Array.Copy(TempBuff, 4 + File0Szie + 4, joinBin_Typ.FileBuff, 0, joinBin_Typ.FileBuff.Length);
                    }
                    else  //长度为空
                    {
                        joinBin_Typ.FileBuff = new byte[0];
                    }
                    UpdataList.Add(joinBin_Typ);
                    Debug.WriteLine("第二个文件: " + ToHexString(UpdataList[1].FileBuff));

                    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                    saveFileDialog1.Title = "请选择解密后保存的路径";
                    saveFileDialog1.Filter = "Bin file(*.Bin)|*.Bin";
                    saveFileDialog1.DefaultExt = ".Bin";
                    if (saveFileDialog1.ShowDialog(this) == DialogResult.OK)
                    {
                        string filepath = saveFileDialog1.FileName;
                        if (UpdataList[0].FileSize>0)
                        {
                            byte[] tempfile = UpdataList[0].FileBuff;
                            AES_Encrypt_Decode_ECB(ref tempfile, AES_KEY, false);
                            FileStream fileStream = new FileStream(filepath+"0", FileMode.CreateNew);
                            fileStream.Write(tempfile,0, (int)UpdataList[0].FileSize);
                            fileStream.Close();
                        }

                        if (UpdataList[1].FileSize > 0)
                        {
                            byte[] tempfile = UpdataList[1].FileBuff;
                            AES_Encrypt_Decode_ECB(ref tempfile, AES_KEY, false);
                            FileStream fileStream = new FileStream(filepath + "1", FileMode.CreateNew);
                            fileStream.Write(tempfile, 0, (int)UpdataList[1].FileSize);
                            fileStream.Close();
                        }
                        textBox4.Text = saveFileDialog1.FileName;
                        MessageBox.Show("拆分成功");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("操作失败 " + ex.Message);
                }






            }
        }
    }
}
